class
	PARSER
inherit
	ARGUMENTS
create
	make, read, process, ptypedef, pvardecl
feature
	system : TYPER

	pexpression( line : STRING) is
		local
			c : CHARACTER
			stream : STRING_INPUT_STREAM
			name : STRING
			stack : STACK[NODE]
			curr  : NODE
			child : NODE
			root  : NODE
		do
			!!stream.from_string(line)
			!!stack.make
			from stream.read_character until stream.end_of_input
			loop
				c := stream.last_character
				if c.same_as('(') then
					stream.read_word_using("() ")
					name := stream.last_string
					!!child.make(name, curr)
					if curr /= Void then
						curr.add_child(child)
					else
						root := child
					end
					curr := child
					stack.push(curr)
				elseif c.same_as(')') then
					curr := stack.top
					stack.pop
				elseif not c.same_as(' ') then
					stream.unread_character
					stream.read_word_using("() ")
					name := stream.last_string
					!!child.make(name, curr)

					curr.add_child(child)
				end

				stream.read_character
			end
			system.add_expr(root)
		end

	ptypedef( args : ARRAY[STRING]) is
		local
			name : STRING
			t    : TYPE
			product : PRODUCT
			subtype : SUBTYPE
			sequence : SEQUENCE
			sum : SUM
			i 	 : INTEGER
		do
			name := args.item(2)
			if args.item(3).is_equal("BASIC") then
				!!t.make(name);
				system.add_type(t)
			elseif args.item(3).is_equal("PRODUCT") then
				!!product.make_product(name)
				from i := 4 until i >= args.count loop
					product.contents.put(system.get_type(args.item(i+1)),args.item(i))
					i := i + 2
				end
				system.add_type(product)
			elseif args.item(3).is_equal("SUM") then
				!!sum.make_sum(name)
				from i := 4 until i >= args.count loop
					sum.contents.put(system.get_type(args.item(i+1)),args.item(i))
					i := i + 2
				end
				system.add_type(sum)
			elseif args.item(3).is_equal("SEQUENCE") then
				!!sequence.make_sequence(name, system.get_type(args.item(4)))
				system.add_type(sequence)
			elseif args.item(3).is_equal("FUNCTION") then
				!FUNCTION_TYPE!t.make_fun(name, system.get_type(args.item(4)), system.get_type(args.item(5)))
				system.add_type(t);
			elseif args.item(3).is_equal("SUBTYPE") then
				product ?= system.get_type(args.item(4))
				!!subtype.make_sub(name, product)
				
				from i := 5 until i >= args.count loop
					subtype.contents.put(system.get_type(args.item(i+1)),args.item(i))
					i := i + 2
				end
				system.add_type(subtype)
			end
		end

	pvardecl( args : ARRAY[STRING]) is
		do
			system.add_value( args.item(2), system.get_type(args.item(3)));
		end

	process (line : STRING) is
		local
			root  : NODE
			words : ARRAY[STRING]
		do
			words := line.split

			if words.count > 0 then
				if words.item(1).is_equal("TYPEDEF") then
					ptypedef(words)
				elseif words.item(1).is_equal("VARDECL") then
					pvardecl(words)
				elseif words.item(1).item(1).same_as('(') then
					pexpression(line)
				elseif words.count > 1 then
					print("Error parsing file at '" + line + "'. If you want to apply a function, surround it with parens. If you want to just have two variables side by side, you are doing it wrong. For now, I'm going to ignore it and continue.%N")
				else
					!!root.make(words.item(1), Void)
					system.add_expr(root)
				end
			end
		end

	read (file : STRING) is
		local
			input : TEXT_FILE_READ
		do
			create input.connect_to(file)
			from
				-- input.read_line
			until
				input.end_of_input
			loop
				input.read_line
				if not input.last_string.is_empty then
					process(input.last_string)
				end
			end
		end

	make is
		local
			--args : ARGUMENTS
		do
			!!system.make
			print("-- This is the output for: " + argument(0) + " " + argument(1) + "%N")
			read(argument(1))
			system.check_types
		end
end
